﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Transactions;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
using System.Web.Security;
using DotNetOpenAuth.AspNet;
using Microsoft.Web.WebPages.OAuth;
using WebMatrix.WebData;
using Board.Filters;
using Board.Models;

namespace Board.Controllers
{
    [Authorize]
    [InitializeSimpleMembership]
    public class AccountController : Controller
    {
        //
        // GET: /Account/Login

        public WebUser currentUser = null;

        protected override void Initialize(RequestContext requestContext)
        {
            base.Initialize(requestContext);
            currentUser = Tools.CurrentUser;
        }

        [AllowAnonymous]
        public ActionResult Login(string returnUrl)
        {
            ViewBag.ReturnUrl = returnUrl;
            return View();
        }

        //
        // POST: /Account/Login

        [HttpPost]
        [AllowAnonymous]
        [ValidateAntiForgeryToken]
        public ActionResult Login(LoginModel model, string returnUrl)
        {
            if (ModelState.IsValid && WebSecurity.Login(model.UserName, model.Password, persistCookie: model.RememberMe))
            {
                return RedirectToLocal(returnUrl);
            }

            // If we got this far, something failed, redisplay form
            ModelState.AddModelError("", "The user name or password provided is incorrect.");
            return View(model);
        }

        //
        // POST: /Account/LogOff

        [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult LogOff()
        {
            WebSecurity.Logout();

            return RedirectToAction("Index", "Home");
        }

        //
        // GET: /Account/Register

        [AllowAnonymous]
        public ActionResult Register()
        {
            return View();
        }

        //
        // POST: /Account/Register

        [HttpPost]
        [AllowAnonymous]
        [ValidateAntiForgeryToken]
        public ActionResult Register(RegisterModel model)
        {
            if (ModelState.IsValid)
            {
                // Attempt to register the user
                try
                {
                    WebSecurity.CreateUserAndAccount(model.UserName, model.Password);
                    WebSecurity.Login(model.UserName, model.Password);
                    return RedirectToAction("Index", "Home");
                }
                catch (MembershipCreateUserException e)
                {
                    ModelState.AddModelError("", ErrorCodeToString(e.StatusCode));
                }
            }

            // If we got this far, something failed, redisplay form
            return View(model);
        }

        //
        // POST: /Account/Disassociate

        [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult Disassociate(string provider, string providerUserId)
        {
            string ownerAccount = OAuthWebSecurity.GetUserName(provider, providerUserId);
            ManageMessageId? message = null;

            // Only disassociate the account if the currently logged in user is the owner
            if (ownerAccount == User.Identity.Name)
            {
                // Use a transaction to prevent the user from deleting their last login credential
                using (var scope = new TransactionScope(TransactionScopeOption.Required, new TransactionOptions { IsolationLevel = IsolationLevel.Serializable }))
                {
                    bool hasLocalAccount = OAuthWebSecurity.HasLocalAccount(WebSecurity.GetUserId(User.Identity.Name));
                    if (hasLocalAccount || OAuthWebSecurity.GetAccountsFromUserName(User.Identity.Name).Count > 1)
                    {
                        OAuthWebSecurity.DeleteAccount(provider, providerUserId);
                        scope.Complete();
                        message = ManageMessageId.RemoveLoginSuccess;
                    }
                }
            }

            return RedirectToAction("Manage", new { Message = message });
        }

        //
        // GET: /Account/Manage

        public ActionResult Manage(ManageMessageId? message)
        {
            ViewBag.StatusMessage =
                message == ManageMessageId.ChangePasswordSuccess ? "Your password has been changed."
                : message == ManageMessageId.SetPasswordSuccess ? "Your password has been set."
                : message == ManageMessageId.RemoveLoginSuccess ? "The external login was removed."
                : "";
            ViewBag.HasLocalPassword = OAuthWebSecurity.HasLocalAccount(WebSecurity.GetUserId(User.Identity.Name));
            ViewBag.ReturnUrl = Url.Action("Manage");
            return View();
        }

        //
        // POST: /Account/Manage

        [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult Manage(LocalPasswordModel model)
        {
            bool hasLocalAccount = OAuthWebSecurity.HasLocalAccount(WebSecurity.GetUserId(User.Identity.Name));
            ViewBag.HasLocalPassword = hasLocalAccount;
            ViewBag.ReturnUrl = Url.Action("Manage");
            if (hasLocalAccount)
            {
                if (ModelState.IsValid)
                {
                    // ChangePassword will throw an exception rather than return false in certain failure scenarios.
                    bool changePasswordSucceeded;
                    try
                    {
                        changePasswordSucceeded = WebSecurity.ChangePassword(User.Identity.Name, model.OldPassword, model.NewPassword);
                    }
                    catch (Exception)
                    {
                        changePasswordSucceeded = false;
                    }

                    if (changePasswordSucceeded)
                    {
                        return RedirectToAction("Manage", new { Message = ManageMessageId.ChangePasswordSuccess });
                    }
                    else
                    {
                        ModelState.AddModelError("", "The current password is incorrect or the new password is invalid.");
                    }
                }
            }
            else
            {
                // User does not have a local password so remove any validation errors caused by a missing
                // OldPassword field
                ModelState state = ModelState["OldPassword"];
                if (state != null)
                {
                    state.Errors.Clear();
                }

                if (ModelState.IsValid)
                {
                    try
                    {
                        WebSecurity.CreateAccount(User.Identity.Name, model.NewPassword);
                        return RedirectToAction("Manage", new { Message = ManageMessageId.SetPasswordSuccess });
                    }
                    catch (Exception e)
                    {
                        ModelState.AddModelError("", e);
                    }
                }
            }

            // If we got this far, something failed, redisplay form
            return View(model);
        }

        //
        // POST: /Account/ExternalLogin

        [HttpPost]
        [AllowAnonymous]
        [ValidateAntiForgeryToken]
        public ActionResult ExternalLogin(string provider, string returnUrl)
        {
            return new ExternalLoginResult(provider, Url.Action("ExternalLoginCallback", new { ReturnUrl = returnUrl }));
        }

        //
        // GET: /Account/ExternalLoginCallback

        [AllowAnonymous]
        public ActionResult ExternalLoginCallback(string returnUrl)
        {
            AuthenticationResult result = OAuthWebSecurity.VerifyAuthentication(Url.Action("ExternalLoginCallback", new { ReturnUrl = returnUrl }));
            if (!result.IsSuccessful)
            {
                return RedirectToAction("ExternalLoginFailure");
            }

            if (OAuthWebSecurity.Login(result.Provider, result.ProviderUserId, createPersistentCookie: false))
            {
                return RedirectToLocal(returnUrl);
            }

            if (User.Identity.IsAuthenticated)
            {
                // If the current user is logged in add the new account
                OAuthWebSecurity.CreateOrUpdateAccount(result.Provider, result.ProviderUserId, User.Identity.Name);
                return RedirectToLocal(returnUrl);
            }
            else
            {
                // User is new, ask for their desired membership name
                string loginData = OAuthWebSecurity.SerializeProviderUserId(result.Provider, result.ProviderUserId);
                ViewBag.ProviderDisplayName = OAuthWebSecurity.GetOAuthClientData(result.Provider).DisplayName;
                ViewBag.ReturnUrl = returnUrl;
                return View("ExternalLoginConfirmation", new RegisterExternalLoginModel { UserName = result.UserName, ExternalLoginData = loginData });
            }
        }

        //
        // POST: /Account/ExternalLoginConfirmation

        [HttpPost]
        [AllowAnonymous]
        [ValidateAntiForgeryToken]
        public ActionResult ExternalLoginConfirmation(RegisterExternalLoginModel model, string returnUrl)
        {
            string provider = null;
            string providerUserId = null;

            if (User.Identity.IsAuthenticated || !OAuthWebSecurity.TryDeserializeProviderUserId(model.ExternalLoginData, out provider, out providerUserId))
            {
                return RedirectToAction("Manage");
            }

            if (ModelState.IsValid)
            {
                // Insert a new user into the database
                using (UsersContext db = new UsersContext())
                {
                    UserProfile user = db.UserProfiles.FirstOrDefault(u => u.UserName.ToLower() == model.UserName.ToLower());
                    // Check if user already exists
                    if (user == null)
                    {
                        // Insert name into the profile table
                        db.UserProfiles.Add(new UserProfile { UserName = model.UserName });
                        db.SaveChanges();

                        OAuthWebSecurity.CreateOrUpdateAccount(provider, providerUserId, model.UserName);
                        OAuthWebSecurity.Login(provider, providerUserId, createPersistentCookie: false);

                        return RedirectToLocal(returnUrl);
                    }
                    else
                    {
                        ModelState.AddModelError("UserName", "User name already exists. Please enter a different user name.");
                    }
                }
            }

            ViewBag.ProviderDisplayName = OAuthWebSecurity.GetOAuthClientData(provider).DisplayName;
            ViewBag.ReturnUrl = returnUrl;
            return View(model);
        }


        [AllowAnonymous]
        public ActionResult ResetAdmin()
        {
            ViewBag.Message = "";
            try
            {
                string token = WebSecurity.GeneratePasswordResetToken("Admin");
                bool result = WebSecurity.ResetPassword(token, "AdminPass12");
                ViewBag.Message = result ? "reset success." : "reset fail.";
            }
            catch 
            {
                ViewBag.Message = "exception happened.";
            }
            return View();
        }

        public ActionResult UserList()
        {
            if (!Tools.CurrentUser.HasSomeAdminPermission)
            {
                return RedirectToAction("Index", "Home");
            }

            ViewBag.Users =
                Tools.CurrentUser.AccessibleUsers.ToList().OrderBy(u => u.LastName).ThenBy(u => u.FirstName).ToList();
            return View();
        }

        public ActionResult UserDetail()
        {
            string userIdStr = Request.Params["userId"];
            WebUser user = Tools.CurrentUser;
            if (!string.IsNullOrEmpty(userIdStr))
            {
                try
                {
                    int userId = int.Parse(userIdStr);
                    user = new WebUser(userId);
                    if (user.UserId <= 0) user = Tools.CurrentUser;
                }
                catch 
                {
                }
            }
            ViewBag.User = user;
            return View();
        }

        public ActionResult UserPermissions()
        {
            string userIdStr = Request.Params["userId"];
            int userId = 0;
            if (!string.IsNullOrEmpty(userIdStr))
            {
                try
                {
                    userId = int.Parse(userIdStr);
                }
                catch { }
            }
            WebUser currentUser = Tools.CurrentUser;
            if (userId > 0)
            {
                WebUser user = new WebUser(userId);
                if (user.UserId > 0 && currentUser.HaveAccessTo(user))
                {
                    ViewBag.User = user;
                }
            }
            var siteDropdown =
                currentUser.AccessibleSites.Select(
                    s =>
                    new SelectListItem()
                        {
                            Selected = s.SiteId.Equals(currentUser.DefaultSite.SiteId),
                            Text = s.SiteId,
                            Value = s.SiteId
                        });
            ViewBag.SiteDropdown = siteDropdown;
            //var unitdropdown = new IEnumerable<SelectListItem>(){new SelectListItem(){Selected = true, Text = "All accessible Units", Value = Unit.ALL_UNITS}};
            List<SelectListItem> unitDropdown =
                currentUser.DefaultSite.AccessibleUnit.Select(s => new SelectListItem() {Text = s.UnitId, Value = s.UnitId}).ToList();
            unitDropdown.Add(new SelectListItem() { Selected = true, Text = "All accessible Units", Value = Unit.ALL_UNITS });
            ViewBag.UnitDropdown = unitDropdown;
            return View();
        }

        public ActionResult SavePermission()
        {
            string userId = Request.Params["userId"];
            string siteId = Request.Params["Site"];
            string unitId = Request.Params["Unit"];
            string bedId = Request.Params["Bed"];
            string action = Request.Params["action"];
            string boardId = Request.Params["boardId"];

            var siteDropdown =
                    currentUser.AccessibleSites.Select(
                        s =>
                        new SelectListItem()
                        {
                            Selected = s.SiteId.Equals(currentUser.DefaultSite.SiteId),
                            Text = s.SiteId,
                            Value = s.SiteId
                        });
            ViewBag.SiteDropdown = siteDropdown;
            //var unitdropdown = new IEnumerable<SelectListItem>(){new SelectListItem(){Selected = true, Text = "All accessible Units", Value = Unit.ALL_UNITS}};
            List<SelectListItem> unitDropdown =
                currentUser.DefaultSite.AccessibleUnit.Select(s => new SelectListItem() { Text = s.UnitId, Value = s.UnitId }).ToList();
            unitDropdown.Add(new SelectListItem() { Selected = true, Text = "All accessible Units", Value = Unit.ALL_UNITS });
            ViewBag.UnitDropdown = unitDropdown;


            if ("delete".Equals(action))
            {
                if (string.IsNullOrEmpty(boardId))
                {
                    ViewBag.Message = "Invalid record.";
                }
                else
                {
                    try
                    {
                        long id = long.Parse(boardId);
                        if (id > 0)
                        {
                            using (DbEntities db = new DbEntities())
                            {
                                var permissions = from p in db.t_UnitBedPermission
                                                  where p.BoardId == id
                                                  select p;
                                
                                if (permissions.Any())
                                {
                                    WebUser user = new WebUser(permissions.FirstOrDefault().UserId);
                                    ViewBag.User = user;
                                    if (currentUser.HaveAccessTo(user))
                                    {

                                        db.t_UnitBedPermission.Remove(permissions.FirstOrDefault());
                                        db.SaveChanges();


                                        ViewBag.Message = "Permission deleted.";
                                    }
                                }
                            }
                        }
                    }
                    catch
                    {
                        ViewBag.Message = "Invalid record";
                    }
                }
            }
            else
            {
                if (!string.IsNullOrEmpty(userId))
                {
                    try
                    {
                        WebUser user = new WebUser(int.Parse(userId));
                        ViewBag.User = user;
                        



                        if (user.HasProfile)
                        {
                            if (currentUser.HaveAccessTo(user))
                            {
                                using (DbEntities db = new DbEntities())
                                {
                                    var permissions = from p in db.t_UnitBedPermission
                                                      where p.UserId == user.UserId &&
                                                            (p.SiteID.Equals(Site.ALL_SITES) || p.SiteID.Equals(siteId)) &&
                                                            (p.UnitID.Equals(Unit.ALL_UNITS) || p.UnitID.Equals(unitId)) &&
                                                            (p.Bed.Equals(Bed.ALL_BEDS) || p.Bed.Equals(bedId))
                                                      select p;
                                    if (permissions.Any())
                                    {
                                        ViewBag.Message = "Permission Exists. No changes.";
                                    }
                                    else
                                    {
                                        //insert new permission
                                        bool unitExist = false;
                                        if (unitId.Equals(Unit.ALL_UNITS))
                                        {
                                            Site site = new Site(siteId);
                                            unitExist = site.Exist && currentUser.HaveAccessTo(site);
                                            bedId = Bed.ALL_BEDS;
                                        }
                                        else if (bedId.Equals(Bed.ALL_BEDS))
                                        {
                                            Unit unit = new Unit(siteId, unitId);
                                            unitExist = unit.Exist && currentUser.HaveAccessTo(unit);
                                        }
                                        else
                                        {
                                            Bed bed = new Bed(siteId, unitId, bedId);
                                            unitExist = bed.Exist && currentUser.HaveAccessTo(bed);
                                        }
                                        if (unitExist)
                                        {
                                            List<t_UnitBedPermission> existingRecords = new List<t_UnitBedPermission>();
                                            if (unitId.Equals(Unit.ALL_UNITS))
                                            {
                                                existingRecords = (db.t_UnitBedPermission.Where(
                                                    e => e.UserId == user.UserId &&
                                                         e.SiteID.Equals(siteId))).ToList();
                                            }
                                            else if (bedId.Equals(Bed.ALL_BEDS))
                                            {
                                                existingRecords = (db.t_UnitBedPermission.Where(
                                                    e => e.UserId == user.UserId &&
                                                         e.SiteID.Equals(siteId) &&
                                                         e.UnitID.Equals(unitId))).ToList();
                                            }
                                            t_UnitBedPermission newRecord = new t_UnitBedPermission()
                                            {
                                                @Bed = bedId,
                                                SiteID = siteId,
                                                UnitID = unitId,
                                                UserId = user.UserId
                                            };
                                            db.t_UnitBedPermission.Add(newRecord);
                                            if (existingRecords.Any())
                                            {
                                                foreach (var tUnitBedPermission in existingRecords)
                                                {
                                                    db.t_UnitBedPermission.Remove(tUnitBedPermission);
                                                }
                                            }

                                            db.SaveChanges();
                                            ViewBag.Message = "Permission added.";
                                        }
                                        else
                                        {
                                            ViewBag.Message = "Invalid Unit information.";
                                        }
                                    }
                                }
                            }
                            else
                            {
                                ViewBag.Message = "Insufficient privileges.";
                            }
                        }
                        else
                        {
                            //wrong user
                            ViewBag.Message = "Invalid User.";
                        }
                    }
                    catch
                    {
                        ViewBag.Message = "Invalid UserID";
                    }
                }
            }
            return View();
        }

        public ActionResult NewUser()
        {
            WebUser currentUser = Tools.CurrentUser;
            ViewBag.CurrentUser = currentUser;
            if (!currentUser.HasSomeAdminPermission)
            {
                return RedirectToAction("Index", "Home");
            }
            if (currentUser.IsAdmin)
            {
                IEnumerable<SelectListItem> defaultSiteList =
                    currentUser.AccessibleSites.Select(
                        s =>
                        new SelectListItem()
                        {
                            Selected = s.SiteId.Equals(currentUser.DefaultSite.SiteId),
                            Text = s.SiteId,
                            Value = s.SiteId
                        }).ToList().OrderBy(s => s.Text);
                ViewBag.DefaultSiteDropdown = defaultSiteList;
            }

            if (currentUser.DefaultSite.Exist)
            {
                IEnumerable<SelectListItem> defaultUnitList =
                    currentUser.DefaultSite.AccessibleUnit.Select(
                        s =>
                        new SelectListItem()
                        {
                            Selected = s.UnitId.Equals(currentUser.DefaultUnit.UnitId+""),
                            Text = s.UnitId,
                            Value = s.UnitId
                        }).ToList().OrderBy(s => s.Text);
                ViewBag.DefaultUnitDropdown = defaultUnitList;
            }

            IEnumerable<SelectListItem> roleList =
                currentUser.AccessibleRoles.Select(
                    r =>
                    new SelectListItem()
                    {
                        Selected = r.RoleName.Equals(Role.ROLE_KARDEX_USER),
                        Text = r.RoleName,
                        Value = r.RoleId + ""
                    });
            ViewBag.RoleDropdown = roleList;

            IEnumerable<SelectListItem> userTypes =
                WebUser.AllUserTypes.Select(
                    t => new SelectListItem() { Selected = t.Equals(WebUser.USER_TYPE_SYSTEM), Text = t, Value = t });
            ViewBag.UserTypeDropdown = userTypes;

            return View();
        }

        public ActionResult ResetPassword()
        {
            string userIdStr = Request.Params["userId"];
            string newPassword = Request.Params["newPassword"];
            WebUser currentUser = Tools.CurrentUser;
            int userId = currentUser.UserId;
            if (!string.IsNullOrEmpty(userIdStr))
            {
                try
                {
                    userId = int.Parse(userIdStr);
                }
                catch
                {
                    ViewBag.Message = "Invalid user information.";
                    return View();
                }
            }
            WebUser user = new WebUser(userId);
            if (!currentUser.HaveAccessTo(user))
            {
                ViewBag.Message = "You do not have access to this user.";
            }
            else
            {
                if (!string.IsNullOrEmpty(newPassword))
                {
                    user.ResetPassword(newPassword);
                    ViewBag.Message = "Password reset successful.";
                }
                else
                {
                    ViewBag.User = user;
                }
            }
            return View();
        }

        public ActionResult UserSave()
        {
            string userIdStr = Request.Params["UserId"];
            string userName = Request.Params["Username"];
            string password = Request.Params["Password"];
            string firstName = Request.Params["FirstName"];
            string lastName = Request.Params["LastName"];
            string userType = Request.Params["UserType"];
            string showAllBedStr = Request.Params["ShowAllBed"];
            string defaultSite = Request.Params["Site"];
            string defaultUnit = Request.Params["Unit"];
            string defaultRecordsPerPageStr = Request.Params["DefaultRecordsPerPage"];
            string rolesStr = Request.Params["Roles"];
            WebUser currentUser = Tools.CurrentUser;

            int userId = 0;
            int defaultRecordsPerPage = 50;
            bool showAllBed = !string.IsNullOrEmpty(showAllBedStr) && "true".Equals(showAllBedStr);

            if (!string.IsNullOrEmpty(userIdStr))
            {
                userId = int.Parse(userIdStr);
            }

            if (!string.IsNullOrEmpty(defaultRecordsPerPageStr))
            {
                try
                {
                    defaultRecordsPerPage = int.Parse(defaultRecordsPerPageStr);
                }
                catch { }
            }


            HashSet<Role> roles = new HashSet<Role>();
            if (!string.IsNullOrEmpty(rolesStr))
            {
                List<int> roleIds = new List<int>();
                var role = rolesStr.Split(',');
                foreach (var s in role)
                {
                    try
                    {
                        roleIds.Add(int.Parse(s));
                    }catch{}
                }
                roles.AddRange(Role.GetRolesById(roleIds).ToList());
            }

            if (currentUser.IsAdmin)
            {
                IEnumerable<SelectListItem> defaultSiteList =
                    currentUser.AccessibleSites.Select(
                        s =>
                        new SelectListItem()
                        {
                            Selected = s.SiteId.Equals(string.IsNullOrEmpty(defaultSite)?currentUser.DefaultSite.SiteId + "":defaultSite),
                            Text = s.SiteId,
                            Value = s.SiteId
                        }).ToList().OrderBy(s => s.Text);
                ViewBag.DefaultSiteDropdown = defaultSiteList;
            }

            if (!string.IsNullOrEmpty(defaultSite) || currentUser.DefaultSite.Exist)
            {
                Site theSite = currentUser.AccessibleSites.FirstOrDefault(s=>s.SiteId.Equals(defaultSite));
                if (theSite==null || string.IsNullOrEmpty(theSite.SiteId))
                {
                    theSite = currentUser.DefaultSite;
                }
                IEnumerable<SelectListItem> defaultUnitList =
                    theSite.AccessibleUnit.Select(
                        s =>
                        new SelectListItem()
                        {
                            Selected = s.UnitId.Equals(string.IsNullOrEmpty(defaultUnit)?currentUser.DefaultUnit.UnitId + "":defaultUnit),
                            Text = s.UnitId,
                            Value = s.UnitId
                        }).ToList().OrderBy(s => s.Text);
                ViewBag.DefaultUnitDropdown = defaultUnitList;
            }

            IEnumerable<SelectListItem> roleList =
                currentUser.AccessibleRoles.Select(
                    r =>
                    new SelectListItem()
                    {
                        Selected = roles.Any(role=>role.RoleId == r.RoleId),
                        Text = r.RoleName,
                        Value = r.RoleId + ""
                    });
            ViewBag.RoleDropdown = roleList;

            IEnumerable<SelectListItem> userTypes =
                WebUser.AllUserTypes.Select(
                    t => new SelectListItem() { Selected = t.Equals(userType), Text = t, Value = t });
            ViewBag.UserTypeDropdown = userTypes;



            ViewBag.Success = false;
            if (!string.IsNullOrEmpty(userName) && !string.IsNullOrEmpty(userType) && !string.IsNullOrEmpty(defaultSite) &&
                !string.IsNullOrEmpty(defaultUnit) && roles.Any())
            {
                if (userId == 0 && !string.IsNullOrEmpty(password))
                {
                    // Attempt to register the user
                    try
                    {
                        WebSecurity.CreateUserAndAccount(userName, password);
                    }
                    catch (MembershipCreateUserException e)
                    {
                        ViewBag.Message = ErrorCodeToString(e.StatusCode);
                        ViewBag.User = new WebUser()
                            {
                                Username = userName,
                                UserType = userType,
                                DefaultSite = new Site(defaultSite),
                                DefaultUnit = new Unit(defaultSite, defaultUnit),
                                FirstName = firstName,
                                LastName = lastName,
                                Roles = roles,
                                ShowAllBed = showAllBed,
                                DefaultRecordsPerPage = defaultRecordsPerPage
                            };
                        return View();
                    }
                }
                var user = new WebUser(userName)
                    {
                        UserType = userType,
                        DefaultSite = new Site(defaultSite),
                        DefaultUnit = new Unit(defaultSite, defaultUnit),
                        FirstName = firstName,
                        LastName = lastName,
                        Roles = roles,
                        ShowAllBed = showAllBed,
                        DefaultRecordsPerPage = defaultRecordsPerPage
                    };
                if (userId == 0)
                {
                    user.CreatedBy = currentUser.UserId;
                    user.CreationDate = DateTime.Now;
                }
                user.Save();
                ViewBag.User = user;
                ViewBag.Success = true;
                ViewBag.Message = "User information is saved successfully.";
            }
            else
            {
                ViewBag.Message = "Username, user type, user role, default site, and default unit is required.";
            }
            return View();
        }

        public ActionResult UserModify()
        {

            string userIdStr = Request.Params["userId"];
            WebUser user = Tools.CurrentUser;
            WebUser currentUser = Tools.CurrentUser;


            if (!string.IsNullOrEmpty(userIdStr))
            {
                try
                {
                    int userId = int.Parse(userIdStr);
                    user = new WebUser(userId);
                    if (user.UserId <= 0 || !Tools.CurrentUser.HaveAccessTo(user)) user = Tools.CurrentUser;
                }
                catch
                {
                }
            }
            if (!currentUser.HaveAccessTo(user))
            {
                return RedirectToAction("UserList");
            }
            ViewBag.CurrentUser = currentUser;
            ViewBag.User = user;
            if (currentUser.HasWebAccess)
            {
                string defaultSite = user.DefaultSite == null? "":user.DefaultSite.SiteId;
                if (string.IsNullOrEmpty(defaultSite)) defaultSite = currentUser.DefaultSite.SiteId;
                IEnumerable<SelectListItem> defaultSiteList =
                    Tools.CurrentUser.AccessibleSites.Select(
                        s =>
                        new SelectListItem()
                        {
                            Selected = s.SiteId.Equals(defaultSite),
                            Text = s.SiteId,
                            Value = s.SiteId
                        }).ToList().OrderBy(s=>s.Text);
                ViewBag.DefaultSiteDropdown = defaultSiteList;

                string defaultUnit = user.DefaultUnit == null ? "":user.DefaultUnit.UnitId;
                if (string.IsNullOrEmpty(defaultUnit) && string.IsNullOrEmpty(defaultSite))
                {
                    defaultUnit = currentUser.DefaultUnit.UnitId;
                }

                IEnumerable<SelectListItem> defaultUnitList =
                    currentUser.AccessibleSites.FirstOrDefault(s => s.SiteId.Equals(defaultSite)).AccessibleUnit.Select(
                        s =>
                        new SelectListItem()
                        {
                            Selected = s.UnitId.Equals(defaultUnit),
                            Text = s.UnitId,
                            Value = s.UnitId
                        }).ToList().OrderBy(s => s.Text);
                ViewBag.DefaultUnitDropdown = defaultUnitList;

                
            }


            IEnumerable<SelectListItem> roleList =
                currentUser.AccessibleRoles.Select(
                    r =>
                    new SelectListItem()
                        {
                            Selected = user.Roles.Select(r2 => r2.RoleId).Contains(r.RoleId),
                            Text = r.RoleName,
                            Value = r.RoleId+""
                        });
            ViewBag.RoleDropdown = roleList;

            IEnumerable<SelectListItem> userTypes =
                WebUser.AllUserTypes.Select(
                    t => new SelectListItem() {Selected = t.Equals(user.UserType), Text = t, Value = t});
            ViewBag.UserTypeDropdown = userTypes;

            return View();
        }

        public ActionResult GetUnitsBySiteId()
        {
            string siteId = Request.Params["siteId"];
            string unitId = Request.Params["unitId"];
            string usage = Request.Params["usage"];
            if (!string.IsNullOrEmpty(usage))
            {
                try
                {
                    ViewBag.Usage = int.Parse(usage);
                }
                catch
                {
                    
                }
            }
            WebUser currentUser = Tools.CurrentUser;
            if (currentUser.HasWebAccess )
            {
                if(!string.IsNullOrEmpty(siteId) && string.IsNullOrEmpty(unitId))
                {
                    var unitDropdown = new List<SelectListItem>();
                    if (string.IsNullOrEmpty(usage)) { }
                    else if( usage.Equals("1"))
                    {
                        unitDropdown.Add(new SelectListItem(){Selected = true, Text = "All available units", Value = Unit.ALL_UNITS});
                    }
                    unitDropdown.AddRange(currentUser.AccessibleSites.FirstOrDefault(s => s.SiteId.Equals(siteId)).AccessibleUnit.Select(
                        u =>
                        new SelectListItem()
                            {
                                Selected = u.UnitId.Equals(currentUser.DefaultUnit.UnitId),
                                Text = u.UnitId,
                                Value = u.UnitId
                            }));
                    ViewBag.DefaultUnitDropdown =unitDropdown;
                }else
                {
                    var bedDropdown = new List<SelectListItem>();
                    if (string.IsNullOrEmpty(usage))
                    {
                        
                    }else
                    if (usage.Equals("1"))
                    {
                        bedDropdown.Add(new SelectListItem() { Selected = true, Text = "All available beds", Value = Bed.ALL_BEDS });
                    }
                    bedDropdown.AddRange(currentUser.AccessibleSites.FirstOrDefault(s => s.SiteId.Equals(siteId)).AccessibleUnit.FirstOrDefault(u=>u.UnitId.Equals(unitId)).AccessibleBeds.Select(
                        u =>
                        new SelectListItem()
                        {
                            Text = u.BedId,
                            Value = u.BedId
                        }));
                    ViewBag.DefaultBedDropdown =bedDropdown;
                }
            }
            return View();
        }


        //
        // GET: /Account/ExternalLoginFailure

        [AllowAnonymous]
        public ActionResult ExternalLoginFailure()
        {
            return View();
        }

        [AllowAnonymous]
        [ChildActionOnly]
        public ActionResult ExternalLoginsList(string returnUrl)
        {
            ViewBag.ReturnUrl = returnUrl;
            return PartialView("_ExternalLoginsListPartial", OAuthWebSecurity.RegisteredClientData);
        }

        [ChildActionOnly]
        public ActionResult RemoveExternalLogins()
        {
            ICollection<OAuthAccount> accounts = OAuthWebSecurity.GetAccountsFromUserName(User.Identity.Name);
            List<ExternalLogin> externalLogins = new List<ExternalLogin>();
            foreach (OAuthAccount account in accounts)
            {
                AuthenticationClientData clientData = OAuthWebSecurity.GetOAuthClientData(account.Provider);

                externalLogins.Add(new ExternalLogin
                {
                    Provider = account.Provider,
                    ProviderDisplayName = clientData.DisplayName,
                    ProviderUserId = account.ProviderUserId,
                });
            }

            ViewBag.ShowRemoveButton = externalLogins.Count > 1 || OAuthWebSecurity.HasLocalAccount(WebSecurity.GetUserId(User.Identity.Name));
            return PartialView("_RemoveExternalLoginsPartial", externalLogins);
        }

        #region Helpers
        private ActionResult RedirectToLocal(string returnUrl)
        {
            if (Url.IsLocalUrl(returnUrl))
            {
                return Redirect(returnUrl);
            }
            else
            {
                return RedirectToAction("Index", "Home");
            }
        }

        public enum ManageMessageId
        {
            ChangePasswordSuccess,
            SetPasswordSuccess,
            RemoveLoginSuccess,
        }

        internal class ExternalLoginResult : ActionResult
        {
            public ExternalLoginResult(string provider, string returnUrl)
            {
                Provider = provider;
                ReturnUrl = returnUrl;
            }

            public string Provider { get; private set; }
            public string ReturnUrl { get; private set; }

            public override void ExecuteResult(ControllerContext context)
            {
                OAuthWebSecurity.RequestAuthentication(Provider, ReturnUrl);
            }
        }

        private static string ErrorCodeToString(MembershipCreateStatus createStatus)
        {
            // See http://go.microsoft.com/fwlink/?LinkID=177550 for
            // a full list of status codes.
            switch (createStatus)
            {
                case MembershipCreateStatus.DuplicateUserName:
                    return "User name already exists. Please enter a different user name.";

                case MembershipCreateStatus.DuplicateEmail:
                    return "A user name for that e-mail address already exists. Please enter a different e-mail address.";

                case MembershipCreateStatus.InvalidPassword:
                    return "The password provided is invalid. Please enter a valid password value.";

                case MembershipCreateStatus.InvalidEmail:
                    return "The e-mail address provided is invalid. Please check the value and try again.";

                case MembershipCreateStatus.InvalidAnswer:
                    return "The password retrieval answer provided is invalid. Please check the value and try again.";

                case MembershipCreateStatus.InvalidQuestion:
                    return "The password retrieval question provided is invalid. Please check the value and try again.";

                case MembershipCreateStatus.InvalidUserName:
                    return "The user name provided is invalid. Please check the value and try again.";

                case MembershipCreateStatus.ProviderError:
                    return "The authentication provider returned an error. Please verify your entry and try again. If the problem persists, please contact your system administrator.";

                case MembershipCreateStatus.UserRejected:
                    return "The user creation request has been canceled. Please verify your entry and try again. If the problem persists, please contact your system administrator.";

                default:
                    return "An unknown error occurred. Please verify your entry and try again. If the problem persists, please contact your system administrator.";
            }
        }
        #endregion
    }
}
